import base64
import math
from io import BytesIO
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
from PIL import Image

order_type = {
    'new': 'New',
    'repeat': 'Repeat',
    'change': 'Change',
    'development': 'R&D'
}
material_status = {
    'S': 'NPI',
    'P': 'MP',
    'T': 'Test',
    'Q': 'QTA+NPI'
}


class report_production_instruction_view(models.AbstractModel):
    _name = 'report.pcbmanufact.report_production_instruction_view'
    _description = 'report_production_instruction_view'

    @api.model
    def _get_report_values(self, docids, data=None):
        self.sudo()
        report = self.env['ir.actions.report']._get_report_from_name('pcbmanufact.report_production_instruction')
        docs = self.env['mrp.production'].with_context(lang='zh_CN').browse(docids)

        # 初始化列表，分别存储不同字段的多个数据
        uom_data_list = []
        spec_values_list = []
        customer_details_list = []
        order_date_list = []
        mo_len_list = []
        order_qty_list = []
        mo_list = []
        order_type_list = []
        panel_num_list = []
        bom_dic_list = []
        x_panel_list = []
        x_panl_qty_list = []
        code_list = []
        first_list = []
        first_id_list = []
        drill_lists = []
        back_drill_lists = []
        drill_image_list = []
        impedance_image_list = []
        impedance_ids_list = []
        ab_make_up_list = []
        lot_list = []
        spec_values_eng_list = []
        image_info_list = []
        too_long_list = []
        hf_pcb_list = []
        for doc in docs:
            # 初始化一些必要的数据
            production_param_values = {}
            production_spec_values = {}
            first_id, mo, too_long = self.get_origin_mo(doc, data)
            uom_data = self.get_unit_number(doc)
            customer_details = self.get_customer_details(first_id, data)
            hf_pcb = ''
            order_type, order_date, order_qty, x_panel, panl_qty, mo_len = self.get_order_qty_date(doc, mo, uom_data, first_id)
            if doc.product_id.categ_id.name == '半成品':
                code_list.append(doc.product_id.name)
                hf_pcb = str(doc.product_id.name)[3] == 'H'
            else:
                code_list.append(doc.product_id.default_code)
                hf_pcb = str(doc.product_id.default_code)[3] == 'H'
            hf_pcb_list.append(hf_pcb)
            # 获取参数值
            for param in doc.param_line_ids:
                if not param.value_id:
                    continue
                value = param.value_id
                param_dict = {
                    'attribute_name': param.attribute_id.name,
                    'value_name': value.name if value else None,
                    'eng_name': value.eng_name if value and value.eng_name else None,
                }
                production_param_values[param.attribute_id.name] = param_dict

            # 获取规格值
            for spec in doc.spec_line_ids:
                spec_dict = {
                    'attribute_name': spec.attribute_id.name,
                    'value_name': spec.value_id.name if spec.value_id else None,
                    'eng_name': spec.value_id.eng_name if spec.value_id and spec.value_id.eng_name else None,
                }
                production_spec_values[spec.attribute_id.name] = spec_dict

            # 合并规格和参数值
            combined_values = production_spec_values.copy()
            combined_values.update(production_param_values)

            # 获取验证数据
            verified_data, verified_data_eng = self.get_verified_data(combined_values)

            # 计算面板数量和面板尺寸
            panel_num = math.ceil(doc.product_qty / uom_data['pcs_in_pnl']) if uom_data['pcs_in_pnl'] else 0
            x_panel = math.ceil(x_panel) if x_panel else None

            ab_makeup = self.get_ab_makeup(doc, mo, panl_qty) if doc.s_makeup_order and doc.product_id == doc.s_makeup_product_id else None

            # 获取 BOM 数据
            bom_dic = self.get_board_uom(doc, x_panel)

            # 将数据添加到对应的列表中
            lot_list.append(self.extract_last_number(doc.name))
            ab_make_up_list.append(ab_makeup)
            first_list.append(first_id.id == doc.id)
            first_id_list.append(first_id)
            uom_data_list.append(uom_data)
            spec_values_list.append(verified_data)
            customer_details_list.append(customer_details)
            order_date_list.append(order_date)
            mo_len_list.append(mo_len)
            order_qty_list.append(order_qty)
            mo_list.append(mo)
            too_long_list.append(too_long)
            order_type_list.append(order_type)
            panel_num_list.append(panel_num)
            bom_dic_list.append(bom_dic)
            x_panel_list.append(x_panel)
            x_panl_qty_list.append(panl_qty)
            drill_list, back_drill_list = self.get_drill_hole_list(doc)
            drill_lists.append(drill_list)
            back_drill_lists.append(back_drill_list)
            # drill_image_list.append(self.get_drill_hole_images(doc))
            spec_values_eng_list.append(verified_data_eng)
            # utilization_list.append(self.get_utilization(doc))
            # 阻抗表
            impedance_image_list.append(doc.product_id.product_tmpl_id.impedance_image if doc.product_id.product_tmpl_id.impedance_image else None)
            impedance_ids_list.append(doc.product_id.product_tmpl_id.impedance_ids if doc.product_id.product_tmpl_id.impedance_ids else None)
            img_info = {}
            if doc.product_id.product_tmpl_id.cutting_drawing_image:
                img_info['cutting_drawing'] = self.get_image_info(doc.product_id.product_tmpl_id.cutting_drawing_image)
            if doc.product_id.product_tmpl_id.stack_up_image:
                img_info['stack_up'] = self.get_image_info(doc.product_id.product_tmpl_id.stack_up_image)
            image_info_list.append(img_info)
        # material_status = self.fields_get(first_id_list[0].product_id.product_tmpl_id.materiel_status) if first_id_list[0].product_id.product_tmpl_id.materiel_status else None
        material_sta = material_status.get(first_id_list[0].product_id.product_tmpl_id.materiel_status) if first_id_list[0].product_id.product_tmpl_id.materiel_status else None
        # 返回包含所有数据的字典
        return {
            'report_obj': self,
            'image_info_list': image_info_list,
            'doc_model': data['context']['active_model'],
            'docs': docs,
            'data': data,
            'uom_data_list': uom_data_list,
            'spec_values_list': spec_values_list,
            'spec_values_eng_list': spec_values_eng_list,
            'ab_make_up_list': ab_make_up_list,
            'customer_details_list': customer_details_list,
            'order_date_list': order_date_list,
            'mo_len_list': mo_len_list,
            'lot_list': lot_list,
            'order_qty_list': order_qty_list,
            'mo_list': mo_list,
            'order_type_list': order_type_list,
            'panel_num_list': panel_num_list,
            'bom_dic_list': bom_dic_list,
            'x_panel_list': x_panel_list,
            'x_panl_qty_list': x_panl_qty_list,
            'code_list': code_list,
            'hf_pcb_list': hf_pcb_list,
            'first_list': first_list,
            'too_long_list': too_long_list,
            'material_status': material_sta,
            'impedance_image_list': impedance_image_list,
            'impedance_ids_list': impedance_ids_list,
            'drill_lists': drill_lists,
            'back_drill_lists': back_drill_lists,
            'drill_image_list': drill_image_list,

        }

    def get_clean_operation_lines(self, wo):
        result_lines = []
        notes_params = []

        for param in wo.param_ids:
            is_notes = param.attribute_id.eng_name and param.attribute_id.eng_name.lower() == 'notes'
            if is_notes:
                notes_params.append(param)
                continue

            if param.value_id:
                attr_name = param.attribute_id.name or False
                attr_eng = param.attribute_id.eng_name or False
                attr_thai = param.attribute_id.thai_name or False

                val_name = param.value_id.name or False
                val_eng = param.z_eng_name or False
                val_thai = param.z_thai_name or False

                result_lines.append({
                    'along': False,
                    'attribute': attr_name,
                    'attribute_eng': attr_eng if attr_eng and attr_eng != attr_name else False,
                    'attribute_thai': attr_thai if attr_thai and attr_thai != attr_name else False,
                    'value': val_name,
                    'value_eng': val_eng if val_eng and val_eng != val_name else False,
                    'value_thai': val_thai if val_thai and val_thai != val_name else False
                })

        # 输出 Notes 作为最后几行（如果存在多个）
        for notes_param in notes_params:
            if notes_param.value_id:
                attr_name = '备注(Notes)'
                val_name = notes_param.value_id.name or False
                val_eng = notes_param.z_eng_name or False
                val_thai = notes_param.z_thai_name or False

                result_lines.append({
                    'along': True,
                    'attribute': attr_name,
                    'attribute_eng': False,
                    'attribute_thai': False,
                    'value': val_name,
                    'value_eng': val_eng if val_eng and val_eng != val_name else '',
                    'value_thai': val_thai if val_thai and val_thai != val_name else '',
                })

        # 工艺段批号（最后两行）
        if wo.workcenter_id.s_process_lot_name:
            result_lines.append({
                'along': True,
                'attribute': wo.workcenter_id.s_process_lot_name + '#:',
                'attribute_eng': False,
                'attribute_thai': False,
                'value': False,
                'value_eng': False,
                'value_thai': False,
            })

        if wo.workcenter_id.s_process_lot_name and wo.workcenter_id.name == '压合':
            result_lines.append({
                'along': True,
                'attribute': "PP_Batch#:",
                'attribute_eng': False,
                'attribute_thai': False,
                'value': False,
                'value_eng': False,
                'value_thai': False,
            })

        return result_lines

    def get_image_info(self, image_field):
        """解析图片，返回图片的原始尺寸、格式以及缩放后的尺寸，保证缩放后高度不超过1400px"""
        try:
            image_data = base64.b64decode(image_field)
            image = Image.open(BytesIO(image_data))
            orig_width = image.width
            orig_height = image.height
            # 按固定宽度1200px计算缩放比例
            scale_by_width = 1100 / orig_width if orig_width else 1
            computed_height = orig_height * scale_by_width
            # 如果计算后的高度超过1400，则以高度为准重新计算缩放比例
            if computed_height > 1400:
                scale = 1400 / orig_height
            else:
                scale = scale_by_width
            scaled_width = int(orig_width * scale)
            scaled_height = int(orig_height * scale)
            return {
                'width': orig_width,
                'height': orig_height,
                'format': image.format,
                'scaled_width': scaled_width,
                'scaled_height': scaled_height,
            }
        except Exception as e:
            return {}

    def extract_last_number(self, text):
        # 从最后一个 "-" 开始分割字符串
        parts = text.rsplit('-', 1)
        if len(parts) == 2:
            number_part = parts[0].split('-')[-1]
            return str(int(number_part))
        else:
            return "1"

    def get_ab_makeup(self, doc, mo, x_panl_qty):
        def get_product_to_production(ab_ids, bp_order):
            product_to_production = {}
            for product in ab_ids:
                # 根据product_id筛选与该产品匹配的生产单
                matching_productions = bp_order.filtered(lambda line: line.product_id == product)
                # 如果找到了匹配的生产单，将其存入字典
                if matching_productions:
                    # 为每个生产单添加比例信息
                    panel = product.uom_value_ids.filtered(lambda x: x.uom_id.name == "PANEL").uom_value
                    sheet = product.uom_value_ids.filtered(lambda x: x.uom_id.name == "SHEET").uom_value
                    product_to_production[product] = [
                        {
                            'default_code': production.product_id.default_code,
                            'product_qty': production.product_qty,
                            'ratio': production.product_qty / x_panl_qty,
                            'panel': int(panel),
                            'sheet': int(sheet),
                            'pcs_in_sheet': int(sheet * panel),
                            'board': production.product_qty / sheet * panel * production.product_qty / x_panl_qty
                        }
                        for production in matching_productions
                    ]
            return product_to_production

        if mo.startswith('RAD') or mo.startswith('M'):
            ab_ids = doc.product_id.product_tmpl_id.makeup_product_ids.mapped('product_id')
            if mo.startswith('RAD'):
                bp_order = doc.s_development_line_ids.mapped('mrp_production_ids').filtered(
                    lambda line: line.state != 'cancel' and line.product_id != doc.s_makeup_product_id
                )
            elif mo.startswith('M'):
                bp_order = doc.s_sale_order_line_ids.mapped('s_mrp_production_ids').filtered(
                    lambda line: line.state != 'cancel' and line.product_id != doc.s_makeup_product_id
                )

            return get_product_to_production(ab_ids, bp_order)

        return {}  # 如果没有匹配的 'mo' 类型，返回空字典

    def get_origin_mo(self, doc, data=None):
        def process_origin(origin):
            """
            处理 origin 字符串，根据逗号数量决定是否换行。
            返回处理后的 origin 和是否过长的标志。
            """
            if origin.count(',') > 2:
                parts = origin.split(',')
                new_origin = []
                for i in range(0, len(parts), 2):
                    new_origin.append(','.join(parts[i:i + 2]))
                origin = '<br/>'.join(new_origin)
                return origin, True
            else:
                origin = origin.replace(',', '<br/>')
                return origin, False

        def _get_top_level_mo(mrp_production):
            """
            递归函数，用于找到最顶层的父工单。
            返回最顶层工单的 id 和 origin。
            """
            if mrp_production.origin:
                # 如果当前工单有来源订单（origin），尝试获取来源订单的父工单
                origin_mo = self.env['mrp.production'].sudo().search([('name', '=', mrp_production.origin)], limit=1)
                if origin_mo:
                    return _get_top_level_mo(origin_mo)  # 递归调用
            # 返回最顶层的工单 id 和 origin
            return mrp_production, mrp_production.origin or mrp_production.name

        if data and data['context']['active_model'] == 'mrp.production':
            if doc.mrp_production_source_count > 0:
                # 获取第一个来源订单
                id = doc._get_sources().ids[0]
                origin_mo = doc.env['mrp.production'].browse(id)
                # 递归查找最顶层的父工单
                top_level_mo_id, top_level_mo_origin = _get_top_level_mo(origin_mo)
                processed_origin, is_too_long = process_origin(top_level_mo_origin)
                return top_level_mo_id, processed_origin, is_too_long  # 返回最顶层工单的 id 和 origin
            else:
                origin = doc.origin or doc.name
                processed_origin, is_too_long = process_origin(origin)
                return doc, processed_origin, is_too_long
        return None, None, False

    def get_board_uom(self, docs, x_panel):
        board_uom_dict = {}
        processed_mo_ids = set()  # 用于记录已经处理过的工单 ID

        def process_moves(moves, doc):
            for move_raw_id in moves:
                is_board_material = (move_raw_id.product_id.categ_id.name == '芯板' or
                                     (move_raw_id.product_id.categ_id.parent_id and move_raw_id.product_id.categ_id.parent_id.name == '芯板'))

                # 判断是否是粘结片或箔类
                is_non_board_material = (move_raw_id.product_id.categ_id.name == '粘结片' or
                                         (move_raw_id.product_id.categ_id.parent_id and move_raw_id.product_id.categ_id.parent_id.name == '粘结片')) or \
                                        (move_raw_id.product_id.categ_id.name == '箔类' or
                                         (move_raw_id.product_id.categ_id.parent_id and move_raw_id.product_id.categ_id.parent_id.name == '箔类'))
                if is_board_material or is_non_board_material:
                    # 获取产品信息
                    product_id = move_raw_id.product_id.id
                    product_name = move_raw_id.product_id.default_code
                    product_des = move_raw_id.product_id.name
                    product_uom = move_raw_id.product_uom.name
                    product_qty = move_raw_id.product_uom_qty / doc.panel_qty * x_panel  # 实际是sheet
                    # panel_need_qty = move_raw_id.panel_need_qty
                    shet_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == 'SHETW').uom_value
                    shet_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == 'SHETL').uom_value
                    are = shet_width * shet_length * product_qty / 1000000  # 计算面积（单位：平方米）

                    # 检查产品是否已在字典中
                    if product_id in board_uom_dict:
                        # 如果产品已存在，更新数量
                        board_uom_dict[product_id]['sheet_need_qty'] += product_qty
                        # board_uom_dict[product_id]['sheet_are'] = shet_width * shet_length * board_uom_dict[product_id]['sheet_need_qty'] / 1000000
                    else:
                        # 如果产品不存在，添加新的条目
                        board_uom_dict[product_id] = {
                            'name': product_name,
                            'des': product_des,
                            'unit': product_uom,
                            'sheet_need_qty': product_qty,
                            'sheet_are': are,
                            'sheet_width': shet_width,
                            'sheet_length': shet_length,
                            'is_board': is_board_material,
                        }
            for product_id in board_uom_dict:
                board_uom_dict[product_id]['sheet_need_qty'] = math.ceil(board_uom_dict[product_id]['sheet_need_qty'])

        # 递归处理子工单
        def process_children(doc):
            # 如果工单已经处理过，则跳过
            if doc.id in processed_mo_ids:
                return
            processed_mo_ids.add(doc.id)  # 标记工单为已处理

            # 处理当前工单的 raw moves
            process_moves(doc.move_raw_ids, doc)

            # 处理子工单
            children = doc._get_children()  # 获取子工单
            if children:
                for child in children:
                    process_children(child)  # 递归调用处理子工单的子工单

        for doc in docs:
            process_children(doc)

        return board_uom_dict

    def get_order_qty_date(self, docs, mo, uom_data, first_id):
        def calculate_panl_qty(doc, order_ids, is_sale_order=False):
            panl_qty = 0
            x_panel = 0
            product_qty = 0
            x = 0
            all_mrp_production_ids = set()  # 用于存放去重后的生产订单

            for order_id in order_ids:
                if is_sale_order:
                    same_product_lines = order_id.order_line.filtered(
                        lambda line: line.product_template_id.id == first_id.product_id.product_tmpl_id.id
                    )
                    product_qty_name = "product_uom_qty"
                    production_ids = 's_mrp_production_ids'  # 对销售单使用s_mrp_production_ids
                else:
                    same_product_lines = order_id.line_ids.filtered(
                        lambda line: line.product_id.id == first_id.product_id.id
                    )
                    product_qty_name = "product_qty"
                    production_ids = 'mrp_production_ids'  # 对非销售单使用mrp_production_ids

                if same_product_lines:
                    product_qty += sum(same_product_lines.mapped(product_qty_name))
                    # 筛选出未取消的生产订单，并计算数量
                    for mpi in same_product_lines.mapped(production_ids).filtered(lambda mpi: mpi.state != 'cancel'):
                        all_mrp_production_ids.add(mpi.id)

            # 计算去重后的工单数量
            for mpi_id in all_mrp_production_ids:
                mpi = self.env['mrp.production'].browse(mpi_id)  # 获取生产订单对象
                x += mpi.product_qty  # 计算工单数量

            if x:
                x_panel += x / uom_data['set_in_pnl'] / uom_data['pcs_in_set']
                panl_qty += x
            else:
                return doc.product_qty, doc.panel_qty, doc.panel_qty * uom_data['set_in_pnl'] * uom_data['pcs_in_set']
            return product_qty, x_panel, panl_qty

        def get_max_seq_no(base_mo):
            # 搜索以 base_mo 开头的记录  这个慢好多  非必要不用 ；  2025-06-26 已优化取值
            record = self.env['mrp.production'].search([('base_mo', '=', base_mo)], order='seq_no desc', limit=1)
            if not record:
                return 1
            # 找到 seq_no 最大的记录
            return record.seq_no

        for doc in docs:
            if mo:
                if mo.startswith('RAD'):
                    s_development = first_id.s_development_line_ids
                    order_ids = s_development.mapped('order_id')
                    if order_ids:
                        # mo_len = len([prod for prod in order_ids[0].line_ids.mapped('mrp_production_ids') if prod.mo_type == 'N'])
                        product_qty, x_panel, panl_qty = calculate_panl_qty(doc, order_ids)
                        # if mo_len == 0:
                        mo_len = get_max_seq_no(first_id.base_mo)
                        return 'R&D', order_ids[0].planned_receiving_date, product_qty, x_panel, panl_qty, mo_len

                elif mo.startswith('M'):
                    s_development = first_id.s_sale_order_line_ids
                    order_ids = s_development.mapped('order_id')
                    if order_ids:
                        product_qty, x_panel, panl_qty = calculate_panl_qty(doc, order_ids, is_sale_order=True)
                        # 获取销售订单的类型和交付日期
                        ot = order_type.get(order_ids[0].order_type)
                        # mo_len = len([prod for prod in order_ids[0].mrp_production_ids if prod.mo_type == 'N'])
                        # if mo_len == 0:
                        mo_len = get_max_seq_no(first_id.base_mo)
                        return ot, order_ids[0].planned_receiving_date, product_qty, x_panel, panl_qty, mo_len
                else:
                    return None, None, doc.product_qty, doc.panel_qty, doc.panel_qty * uom_data['set_in_pnl'] * uom_data['pcs_in_set'], 1

        raise UserError(_('No order found'))

    def get_customer_details(self, first_id, data=None):
        if data['context']['active_model'] == 'mrp.production':
            product_id = first_id.product_id if not first_id.s_makeup_order else first_id.s_makeup_product_id
            product_template = product_id.product_tmpl_id
            customer = first_id.customer
            if not customer or not product_id:
                return None
            else:
                codes = product_id.with_context(active_test=False).customer_item_code_ids
                if codes:
                    customer_detail = self.env['customer.item.code'].with_context(
                        active_test=False
                    ).search([
                        ('product_id', '=', product_template.id),
                        ('customer_id', '=', customer.id)
                    ], order='active asc, id desc', limit=1)  # 優先以 active 升序排列，然後以 id 倒序排列
                    return customer_detail
        return None

    # 数据整理
    def get_verified_data(self, combined_values):
        dic = {
            '层数': None,
            '内层基铜厚': None,
            '内层完成铜厚': None,
            '外层基铜厚': None,
            '外层完成铜厚': None,
            '外型公差': None,
            '成品板厚': None,
            '板厚公差': None,
            '板厚测点': None,
            '板子特性': None,
            '压合程式': None,
            '制作人': None,
            '表面处理': None,
            '叉板率': None,
            '激光孔厚径比': None,
            'BD2C背钻孔-内层铜': None,
            'Tg': None,
            '通孔厚径比': None,
            'X-Out(叉板)': None,
            'D2C机械孔-内层铜': None,
            'DHS机械孔': None,
            '长边工艺边': None,
            '短边工艺边': None,
            'D2D不同网络孔边-孔边': None,
            'LDS激光孔': None,
            '产品类别': None,
            '附注': None,
            '注解': None,
            '难度等级': None,
            '线路工艺': None,
            '测量位置Top': None,
            '测量位置Bot': None,
            '板上型号': None,
            '产品特征': None,
            '利用率': None,
            '产品应用': None,
        }
        dic_eng = {
            '表面处理': None,
            '板厚测点': None,
            '线路工艺': None,
            '测量位置Bot': None,
            '测量位置Top': None,
        }
        for key, value in combined_values.items():
            if key in dic:  # 如果字典dic中存在这个key
                dic[key] = value['value_name']  # 将dic中的value更新为value_name的值
            if key in dic_eng:
                dic_eng[key] = value['eng_name']
            # else: #追加
            #     dic[key] = value['value_name']
        return dic, dic_eng

    def get_unit_number(self, docs):
        def format_number(value):
            """
            格式化数字，去除多余的零和小数点。
            """
            if value.is_integer():  # 检查是否为整数
                return int(value)  # 转换为整数
            else:
                return value  # 保留小数部分

        uom_panel_width = self.env.ref('pcbmanufact.uom_panel_width')
        uom_panel_length = self.env.ref('pcbmanufact.uom_panel_length')
        uom_set_width = self.env.ref('pcbmanufact.uom_set_width')
        uom_set_length = self.env.ref('pcbmanufact.uom_set_length')
        uom_pcs_width = self.env.ref('pcbmanufact.uom_pcs_width')
        uom_pcs_length = self.env.ref('pcbmanufact.uom_pcs_length')
        uom_set = self.env.ref('pcbmanufact.uom_set')
        uom_pcs = self.env.ref('pcbmanufact.uom_part')  # pcs
        uom_panel = self.env.ref('pcbmanufact.uom_panel')
        uom_ids = docs.uom_value_ids.mapped('uom_id')

        if uom_panel_width in uom_ids and uom_panel_length in uom_ids and uom_set_width in uom_ids and uom_set_length in uom_ids:
            pnl_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_panel_width.id).uom_value
            pnl_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_panel_length.id).uom_value
            set_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_set_width.id).uom_value
            set_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_set_length.id).uom_value
            pcs_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_pcs_width.id).uom_value
            pcs_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_pcs_length.id).uom_value
            panel = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_panel.id).uom_value
            pcs = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_pcs.id).uom_value
            set = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_set.id).uom_value
            # sheet_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == "SHETL").uom_value
            # sheet_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == "SHETW").uom_value
            sheet = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == "SHEET").uom_value
            # 判断是否不为0
            if pnl_width and pnl_length and set_width and set_length and pcs_width and pcs_length and panel and pcs and set and sheet:
                pass
            else:
                raise UserError(_('Please input all unit of measure values'))

            # sheet_size_string = str(sheet_width) + ' * ' + str(sheet_length)
            # sheet_are = float(sheet_width) * float(sheet_length) / 1000000
            pnl_are = float(pnl_width) * float(pnl_length) / 1000000
            pnl_size_string = f"{format_number(pnl_length)} * {format_number(pnl_width)}"
            set_size_string = f"{format_number(set_width)} * {format_number(set_length)}"
            pcs_size_string = f"{format_number(pcs_width)} * {format_number(pcs_length)}"
            set_in_pnl = int(panel / set)
            pcs_in_pnl = int(panel / pcs)
            pcs_in_set = int(set / pcs)
            # pnl_in_sheet = math.floor((float(sheet_width) * float(sheet_length)) / (float(pnl_width) * float(pnl_length)))
            set_in_sheet = sheet * set_in_pnl
            uom_details = {
                'pln_size': pnl_size_string,
                'set_size': set_size_string,
                'pcs_size': pcs_size_string,
                # 'sheet_size': sheet_size_string,
                'set_in_pnl': set_in_pnl,
                'pcs_in_pnl': pcs_in_pnl,
                'pcs_in_set': pcs_in_set,
                'set_in_sheet': set_in_sheet,
                # 'sheet_are': sheet_are,
                'pnl_are': pnl_are,
            }
        else:
            raise UserError(_('Fields are missing or do not match. Please Check whether \n [PNLL PNLW PCS SET PANEL SetL SetW PCSL PCSW] exist'))

        return uom_details

    def get_drill_hole_list(self, doc):
        drill_list = []
        back_drill_list = []
        if not doc.workorder_ids:
            return None
        for wo in doc.workorder_ids:
            if wo.s_drill_operation_ids:
                drill_list.append(wo.s_drill_operation_ids)
            if wo.s_back_drill_operation_ids:
                back_drill_list.append(wo)
        return drill_list, back_drill_list

    # 钻孔图
    # def get_drill_hole_images(self, doc):
    #     images = []  # 创建一个空列表来存储所有找到的图片
    #     if not doc.bom_id:
    #         return None
    #     for bom in doc.bom_id:  # BOM
    #         for operation in bom.operation_ids:  # 遍历每个操作
    #             if operation.drill_image:  # 如果存在钻孔图
    #                 images.append(operation.drill_image)  # 添加到列表中
    #     return images if images else None  # 返回包含所有图片的列表

    # 钻孔表
    # def get_drill_hole_list(self, doc):
    #     drill_list = []
    #     if not doc.bom_id:
    #         return None
    #     for bom in doc.bom_id:
    #         for operation in bom.operation_ids:
    #             if operation.drill_operation_ids:
    #                 drill_list.append(operation.drill_operation_ids)
    #     return drill_list if drill_list else None
